home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1993 / MacHack 1993.toast / MacHack™ 1987-1992 / MacHack™ '90 / Source Code ƒ / Misc. Pascal ƒ / Jay's Cookie / Bake.p < prev    next >
Encoding:
Text File  |  1990-06-15  |  11.4 KB  |  433 lines  |  [TEXT/MPS ]

  1. {[n+,u+,r+,d+,#+,j=13-/40/1o,t=2,o=95] PasMat formatting options}
  2.  
  3. {------------------------------------------------------------------------------
  4.  
  5.     Bake.p by D. Jay Newman;  I release this into the public domain
  6.  
  7.  
  8. FILE Bake.p
  9.  
  10. NAME
  11.     Bake -- converts a fortune cookie file from text to internal format
  12.  
  13. SYNOPSIS
  14.     Bake inputFileName outputFileName
  15.  
  16. DESCRIPTION
  17.     A pure unix-syle filter, which will convert the input file (which should be of
  18.     type TEXT into the file format prefered by my fortune cookie DA).  The file
  19.     format is as follows:
  20.         Number of Cookies (n):            LONGINT;
  21.         Text offsets of each cookie:    ARRAY [1..n] OF LONGINT
  22.         Text offset of end of file:        LONGINT;
  23.         Cookie Text:                    Text;    --Cookies are separated by 0's--
  24.  
  25.     The start of the text is calculated:
  26.         (Number of Cookies + 2) * SizeOf (LONGINT)
  27.  
  28.     The offset of cookie i is
  29.         (i * SizeOf (LONGINT))
  30.  
  31.     The length of cookie i is
  32.         (Offset of cookie i) - (Offset of cookie i+1)
  33.  
  34.     Input File Format:
  35.         A basic text file, if there is a RETURN at the end of the line, and the
  36.         cookie is not ended, then the next line will be joined (the RETURN changed
  37.         to a space), unless the next line begins with a non-alphanumeric character.
  38.         Special lines are the following:
  39.             %%    - End of cookie
  40.             $$    - Skip this line (add a return here and at end of previous line)
  41.  
  42. MODIFICATIONS
  43.     2/22/90
  44.         Originally, I did all the temp stuff in memory.  Now I will use a temp
  45.         file to store the text until I write it to the real file.
  46. ------------------------------------------------------------------------------}
  47. {$R-}          { Turn off range checking}
  48. PROGRAM Bake;
  49.  
  50. USES    { $Load macstuff}
  51.     Memtypes, Quickdraw, OSIntf, ToolIntf, PackIntf, { Standard Includes}
  52.     { $Load mpwstuff}
  53.     CursorCtl,                        {for the spinning cursor}
  54.     Signal,                         {to handle command-period}
  55.     PasLibIntf,                     {for standard I/O, etc.}
  56.     IntEnv;                         {for argV and argC}
  57.  
  58.  
  59. TYPE
  60.     LongPtr = ^LONGINT;
  61.  
  62. CONST
  63.     Version            = '0.9.1';         {Current version}
  64.     kCookieSize        = 20000;        {One big mama of a cookie!}
  65.     kOffsetSize        = 100000;        {Up to 25,000 cookies!}
  66.  
  67. VAR
  68.     textName:        Str255;            {the names of the files}
  69.     realName:         Str255;            {name of output file}
  70.     tempName:        Str255;            {name of temp file}
  71.     quiet:            Boolean;         { True ==> no info on Diagnostic file}
  72.     progName:        Str255;            { Program's file name}
  73.     interrupted:    Boolean;        {True ==> interrupted (Opt "." pressed)}
  74.     retCode:        (RC_Normal, RC_ParmErrs, RC_Abort); {Return codes}
  75.  
  76.     textCookies:        TEXT;                {This is a text file}
  77.     realCookies:        FILE;                {This is an untyped file}
  78.     tempCookies:        FILE;                {This is an untyped file, consisting
  79.                                                 of the modified cookie text, but
  80.                                                 not the offsets}
  81.     cookieBuffer:        Handle;                {current formatted cookie}
  82.     textLen:            LONGINT;            {length of formatted text}
  83.     bufLen:                LONGINT;            {length of current cookie buffer}
  84.     numCookies:            LONGINT;            {number of cookies formatted}
  85.     curOffset:            LONGINT;            {offset of current cookie}
  86.     prevOffset:            LONGINT;            {offset of previous cookie}
  87.     theOffsets:            Handle;                {array of offsets: numCookies is number}
  88.     addSpace:            BOOLEAN;            {FALSE only when $$ line found}
  89.  
  90.     {[j=0] PasMat formatting option}
  91.  
  92.     {*----------------------------------*
  93.     | Stop - terminate execution        |
  94.     *----------------------------------*}
  95.  
  96.     PROCEDURE Stop(msg: Str255);
  97.     BEGIN                                                          {Stop}
  98.         IF Length(msg) > 0 THEN
  99.             BEGIN
  100.                 PLFlush (Output);
  101.                 WriteLn(Diagnostic);
  102.                 WriteLn(Diagnostic, msg);
  103.             END;
  104.  
  105.         IF interrupted THEN retCode := RC_Abort;
  106.         {don't worry about closing the files we opened.  The Shell
  107.             will do so if appropriate.}
  108.         IEexit(Ord(retCode));            {exit, returning the appropriate status code}
  109.     END;        {Stop}
  110.  
  111.     {*--------------------------------------*
  112.     | Intr - Process external interrupt        |
  113.     | this routine is passed to IEsigset    |
  114.     *--------------------------------------*}
  115.  
  116.     PROCEDURE Intr;
  117.     BEGIN         {Intr}
  118.         interrupted := True;                {we test this switch periodically}
  119.     END;        {Intr}
  120.  
  121.     {$S Init}
  122.  
  123.     {*-------------------------------------------------------------*
  124.      | SyntaxError - Report an error in parameters or options        |
  125.      *-------------------------------------------------------------*}
  126.  
  127.     PROCEDURE SyntaxError(suffix: Str255);
  128.     BEGIN        {SyntaxError}
  129.         PLFlush (Output);
  130.         WriteLn(Diagnostic, '### ', progName, ' - ', suffix);
  131.         Stop(Concat('# Usage: ', progName, ' file1 file2'));
  132.     END;        {SyntaxError}
  133.  
  134.     {*--------------------------------------*
  135.      | LetterOpt - Set a letter option        |
  136.      *-------------------------------------*}
  137.  
  138.     PROCEDURE LetterOpt(opt: Char; VAR argVIndex: integer);
  139.         {note no options are supported; argVIndex is passed to
  140.              this routine so options that have arguments can 'eat' them}
  141.     BEGIN        {LetterOpt}
  142.         SyntaxError(Concat(ArgV^[argVIndex]^, ' <invalid option>'));
  143.     END;        {LetterOpt}
  144.  
  145.     {*---------------------------*
  146.     | Init - Tool initalization |
  147.     *---------------------------*}
  148.  
  149.     PROCEDURE Init;
  150.     VAR
  151.         ioRslt:                INTEGER;
  152.         argVIndex:            INTEGER;
  153.         fileCount:            INTEGER;
  154.         holdIndex:            INTEGER;
  155.         prevSig:             SignalHandler;
  156.         strH:                StringHandle;
  157.         nextFileNamePtr:    StringPtr;
  158.         arg:                Str255;
  159.         p:                    LongPtr;
  160.     BEGIN        {Init}
  161.         retCode := RC_Normal;
  162.  
  163.         addSpace := TRUE;
  164.  
  165.         interrupted := False;                      {becomes True when interrupted}
  166.         prevSig := IEsignal(SIGINT, @Intr);
  167.  
  168.         quiet := True;
  169.         progName := ArgV^[0]^;
  170.  
  171.         fileCount := 0;
  172.         retCode := RC_ParmErrs;
  173.         argVIndex := 1;
  174.  
  175.         WHILE argVIndex < ArgC DO                     {ArgC is the number of args plus one}
  176.             BEGIN
  177.                 arg := ArgV^[argVIndex]^;
  178.                 IF (Length(arg) <> 0) THEN
  179.                     BEGIN
  180.                         IF arg[1] = '-' THEN            {we have an option }
  181.                             BEGIN
  182.                                 holdIndex := argVIndex;
  183.                                 LetterOpt(arg[2], argVIndex);
  184.                                 IF argVIndex <> holdIndex THEN
  185.                                     CYCLE;                 {skip the increment of argVIndex below}
  186.                             END
  187.                         ELSE                            {it must be a file to open}
  188.                             BEGIN
  189.                                 fileCount := fileCount + 1;
  190.                                 IF fileCount = 1 THEN
  191.                                     nextFileNamePtr := @textName
  192.                                 ELSE
  193.                                     nextFileNamePtr := @realName;
  194.  
  195.                                 nextFileNamePtr^ := ArgV^[argVIndex]^;
  196.                             END;
  197.                     END;
  198.                 argVIndex := argVIndex + 1;
  199.             END;
  200.  
  201.         IF fileCount <> 2 THEN
  202.                 SyntaxError('Invalid Parameters');
  203.  
  204.         Open (textCookies, textName);
  205.         IF Eof (textCookies) OR (IOResult <> 0) THEN
  206.             Stop(Concat('### ', progName, ' - ', 'could not open ', textName));
  207.  
  208.         Rewrite (realCookies, realName);
  209.         IF IOResult <> 0 THEN
  210.             Stop(Concat('### ', progName, ' - ', 'could not open ', realName));
  211.  
  212.         Open (tempCookies, 'TttempCookies');
  213.         IF IOResult <> 0 THEN
  214.             Stop( Concat ('### ', progName, ' - ', 'could not open TttempCookies'));
  215.  
  216.         IF NOT quiet THEN
  217.             BEGIN
  218.                 WriteLn(Diagnostic);
  219.                 WriteLn(Diagnostic, progName, '  (Ver ', Version, ') ');
  220.                 WriteLn(Diagnostic);
  221.                 WriteLn(Diagnostic);
  222.             END;
  223.  
  224.         retCode := RC_Abort;
  225.  
  226.         cookieBuffer := NewHandle (kCookieSize);
  227.         theOffsets := NewHandle (kOffsetSize);
  228.  
  229.         IF (cookieBuffer = NIL) OR (theOffsets = NIL) THEN
  230.             Stop (Concat ('### ', progName, ' - ', 'could not allocate memory'));
  231.  
  232.         retCode := RC_Normal;
  233.  
  234.         textLen := 0;
  235.         bufLen := 0;
  236.         numCookies := 0;
  237.  
  238.         {Put a zero as first offset}
  239.         HLock (theOffsets);
  240.         p := LongPtr (theOffsets^);
  241.         p^ := textLen;
  242.         HUnlock (theOffsets);
  243.  
  244.         RotateCursor(0);
  245.         IF interrupted THEN Stop('');
  246.     END;        {Init}
  247.  
  248.     {$S Main}
  249.     {*---------------------------------------------*
  250.      | BufferToText -- add the buffer to the text  |
  251.      *---------------------------------------------*}
  252.     PROCEDURE BufferToText;
  253.     VAR
  254.         i:        INTEGER;
  255.         p:        LongPtr;
  256.     BEGIN
  257.         {add one to the number of cookies}
  258.         numCookies := numCookies + 1;
  259.  
  260.         HLock (cookieBuffer);
  261.  
  262.         i := ByteWrite (tempCookies, cookieBuffer^^, bufLen);
  263.         textLen := textLen + bufLen;
  264.         bufLen := 0;
  265.  
  266.         HUnlock (cookieBuffer);
  267.  
  268.         {Put offset to next cookie}
  269.         HLock (theOffsets);
  270.         p := LongPtr (Ord4 (theOffsets^) + (numCookies * SizeOf (LONGINT)));
  271.         p^ := textLen;
  272.         HUnlock (theOffsets);
  273.     END;
  274.  
  275.     {*--------------------------------------------------------*
  276.      | AlphaNum -- returns TRUE if character is alphanumeric  |
  277.      *--------------------------------------------------------*}
  278.      FUNCTION AlphaNum (c: CHAR):    BOOLEAN;
  279.      BEGIN
  280.          IF ((c >= '0') AND (c <= '9')) OR
  281.                     ((c >= 'A') AND (c <= 'Z')) OR
  282.                     ((c >= 'a') AND (c <= 'z')) THEN
  283.             AlphaNum := TRUE
  284.         ELSE
  285.             AlphaNum := FALSE;
  286.     END;
  287.  
  288.  
  289.     {*--------------------------------------------------*
  290.      | AddToBuffer -- add a string to the cookie buffer |
  291.      *--------------------------------------------------*}
  292.      PROCEDURE AddToBuffer (s: Str255);
  293.      VAR
  294.          ch:        CHAR;
  295.      BEGIN
  296.         IF bufLen > 0 THEN                {Don't do this the first time}
  297.             BEGIN
  298.                 IF AlphaNum (s[1]) THEN
  299.                     BEGIN
  300.                         IF addSpace THEN
  301.                             BEGIN
  302.                                 s := Concat (' ', s)
  303.                             END
  304.                         ELSE
  305.                             BEGIN
  306.                                 addSpace := TRUE;
  307.                             END;
  308.                     END
  309.                 ELSE
  310.                     BEGIN
  311.                         IF s = '$$' THEN    {Skip a line}
  312.                             BEGIN
  313.                                 s := Concat (Chr (13), Chr (13));
  314.                                 addSpace := FALSE;
  315.                             END
  316.                         ELSE IF s = '!!' THEN    {Put in a return}
  317.                             BEGIN
  318.                                 s := Chr (13);
  319.                                 addSpace := FALSE;
  320.                             END
  321.                         ELSE
  322.                             BEGIN            {Add return then string}
  323.                                 IF addSpace THEN
  324.                                     BEGIN
  325.                                         s := Concat (Chr (13), s);
  326.                                     END;
  327.                                 addSpace := TRUE;
  328.                             END;
  329.                     END;
  330.             END;
  331.  
  332.          HLock (cookieBuffer);
  333.         BlockMove (Ptr (Ord4 (@s) + 1), Ptr (Ord4 (cookieBuffer^) + bufLen),
  334.                     LENGTH (s));
  335.                     
  336.         bufLen := bufLen + LENGTH (s);
  337.         HUnlock (cookieBuffer);
  338.     END;
  339.  
  340.  
  341.     {*------------------------------------------------------*
  342.      | WriteCookieFile -- write the formatted data to disk    |
  343.      *------------------------------------------------------*}
  344.      PROCEDURE WriteCookieFile;
  345.     VAR
  346.         i:        LONGINT;        {dummy variable}
  347.         p:        LongPtr;
  348.         b:        ARRAY [0..511] OF Byte;        {A basic 512 byte buffer}
  349.         n, tL:    LONGINT;
  350.     BEGIN
  351.          {Write number of cookies}
  352.         p := @numCookies;
  353.          i := ByteWrite (realCookies, numCookies, SizeOf (LONGINT));
  354.  
  355.         {Write offset array}
  356.         HLock (theOffsets);
  357.         i := ByteWrite (realCookies, theOffsets^^, (numCookies + 1) * SizeOf (LONGINT));
  358.         HUnlock (theOffsets);
  359.  
  360.         {Write the text info}
  361.         Seek (tempCookies, 0);    {Go back to beginning}
  362.  
  363.         tL := textLen;
  364.         n := 512;                {Transfer data in 512 byte chunks}
  365.         WHILE tL > 0 DO
  366.             BEGIN
  367.                 IF textLen < 512 THEN n := tL;
  368.                 i := ByteRead (tempCookies, b, n);
  369.                 tL := tL - i;
  370.                 i := ByteWrite (realCookies, b, i);
  371.  
  372.                 SpinCursor (-1);
  373.             END;
  374.  
  375.       {    Report on the number of cookies baked}
  376.         WriteLn ('Number of cookies baked: ', numCookies);
  377.         WriteLn ('Total filelength: ', textLen + ((numCookies + 1)
  378.                         * SizeOf (LONGINT)));
  379.     END;
  380.  
  381.  
  382.     {*-------------------------------*
  383.      | DoIt -- actually fix cookies  |
  384.      *-------------------------------*}
  385.     PROCEDURE DoIt;
  386.     VAR
  387.         n:            LONGINT;        {Number of cookies}
  388.         i:            LONGINT;        {Cookie currently processing}
  389.         s:            Str255;            {Current line of text}
  390.     BEGIN
  391.         WHILE NOT Eof (textCookies) DO
  392.             BEGIN
  393.                 ReadLn (textCookies, s);
  394.                 IF IOResult <> 0 THEN
  395.                     Stop (Concat ('### ', progName, ' - ',
  396.                         'problems reading file'));
  397.  
  398.                 IF s = '%%' THEN
  399.                     BEGIN
  400.                         BufferToText;
  401.                         addSpace := TRUE;
  402.                     END
  403.                 ELSE
  404.                     BEGIN
  405.                         AddToBuffer (s);
  406.                     END;
  407.  
  408.                 SpinCursor (1);
  409.             END;
  410.  
  411.         WriteCookieFile;
  412.  
  413.         Close (realCookies);            {Close files nicely}
  414.         Close (textCookies);
  415.         Close (tempCookies);
  416.  
  417.         PLPurge ('TttempCookies');        {Delete this file}
  418.  
  419.         DisposHandle (theOffsets);        {Dispose of handles used}
  420.         DisposHandle (cookieBuffer);
  421.     END;
  422.  
  423.  
  424. {*-----------------------*
  425.  | Bake -- main program  |
  426.  *-----------------------*}
  427.  
  428. BEGIN        {Bake}
  429.     Init;                    { sets up world, opens our resource files}
  430.     UnLoadSeg(@Init);         { release our initialization segment}
  431.     DoIt;                     { and call our routine}
  432. END.        {Bake}
  433.